//@author A0096759E

package googlecal;
/*
 * Credits to:
 * Christopher Deckers (chrriis@nextencia.net)
 * http://www.nextencia.net
 *
 * See the file "readme.txt" for information on usage and redistribution of
 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
 */



import java.awt.BorderLayout;
import java.awt.Point;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URL;

import javax.net.ssl.HttpsURLConnection;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

import applogger.AppLogger;
import chrriis.common.UIUtils;
import chrriis.dj.nativeswing.swtimpl.NativeInterface;
import chrriis.dj.nativeswing.swtimpl.components.JWebBrowser;
import chrriis.dj.nativeswing.swtimpl.components.WebBrowserCommandEvent;
import chrriis.dj.nativeswing.swtimpl.components.WebBrowserEvent;
import chrriis.dj.nativeswing.swtimpl.components.WebBrowserListener;
import chrriis.dj.nativeswing.swtimpl.components.WebBrowserNavigationEvent;
import chrriis.dj.nativeswing.swtimpl.components.WebBrowserWindowOpeningEvent;
import chrriis.dj.nativeswing.swtimpl.components.WebBrowserWindowWillOpenEvent;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

public class GoogleAuthenticatorUI extends JPanel {
	
	private static JFrame frame = new JFrame("Google Authentication");
	private static final String GOOGLE_AUTH_URL = "https://accounts.google.com/o/oauth2/auth?scope=https://www.googleapis.com/auth/calendar%20https://www.googleapis.com/auth/tasks&redirect_uri=urn:ietf:wg:oauth:2.0:oob&response_type=code&client_id=1079490727688-r618gsjrr2robdgrl2maoh5rel32mku4.apps.googleusercontent.com";
	private static final String GOOGLE_VALIDATE_TOKEN_URL = "https://accounts.google.com/o/oauth2/token";
	private static final String GOOGLE_VALIDATE_QUERY = "code=%s&client_id=1079490727688-r618gsjrr2robdgrl2maoh5rel32mku4.apps.googleusercontent.com&client_secret=9h2Z7cQ2e8XjmeKMYgNKKqkj&redirect_uri=urn:ietf:wg:oauth:2.0:oob&grant_type=authorization_code";

	protected static final String STATUS_CODE_STARTER = "Success code=";
	protected static final String STATUS_CODE_DENIED = "Denied error=access_denied";
	protected static final String LOGGER_CURRENT_PAGE_TITLE = "Current Page Title: %s";
	private static final String LOGGER_VALIDATE_ACCESS_TOKEN = "Validate Access Token Response Code : %s";
	private static final String REQUEST_TYPE_POST = "POST";
	private static final String REQUEST_CONTENT_TYPE = "Content-Type";
	private static final String CONTENT_TYPE_FORM_ENCODED = "application/x-www-form-urlencoded";
	
	/**
	 * Constructor for GoogleAuthenticatorUI
	 */
	public GoogleAuthenticatorUI() {
	    super(new BorderLayout());
	    JPanel webBrowserPanel = new JPanel(new BorderLayout());
	    final JWebBrowser webBrowser = new JWebBrowser();
	    webBrowser.navigate(GOOGLE_AUTH_URL);
	    webBrowser.setBarsVisible(false);
	    
	    webBrowser.addWebBrowserListener(new WebBrowserListener() {
			
			public void titleChanged(WebBrowserEvent browserTitleHasChanged) {
				// TODO Auto-generated method stub
				String currentPageTitle = webBrowser.getPageTitle(); 
				if (currentPageTitle != null) { 
					if (currentPageTitle.indexOf(STATUS_CODE_STARTER) == 0) {
						currentPageTitle = currentPageTitle.substring(currentPageTitle.indexOf('=')+1);
						AppLogger.log(String.format(LOGGER_CURRENT_PAGE_TITLE, currentPageTitle));
						webBrowser.removeWebBrowserListener(this);
						try {
							validateAccessToken(currentPageTitle);
						} catch (Exception e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					}
					else if (currentPageTitle.indexOf(STATUS_CODE_DENIED) == 0) {
						AppLogger.log(String.format(LOGGER_CURRENT_PAGE_TITLE, currentPageTitle));
						webBrowser.removeWebBrowserListener(this);
						frame.setVisible(false);
						frame.dispose();
					}
				}
			}
			
			//Mandatory but redundant events
			public void statusChanged(WebBrowserEvent arg0) {}
			public void locationChanging(WebBrowserNavigationEvent arg0) {}
			public void locationChanged(WebBrowserNavigationEvent arg0) {}
			public void locationChangeCanceled(WebBrowserNavigationEvent arg0) {}
			public void loadingProgressChanged(WebBrowserEvent arg0) {}
			public void commandReceived(WebBrowserCommandEvent arg0) {}
			public void windowWillOpen(WebBrowserWindowWillOpenEvent arg0) {}
			public void windowOpening(WebBrowserWindowOpeningEvent arg0) {}
			public void windowClosing(WebBrowserEvent arg0) {}
		});
	    
	    webBrowserPanel.add(webBrowser, BorderLayout.CENTER);
	    add(webBrowserPanel, BorderLayout.CENTER);
	}

	/**
	 * Takes in a Point type location to position the Google Authenticator window, and displays the window.
	 * @param loc - coordinates for creating auth window
	 */
	public void initAuth(final Point loc) {
		UIUtils.setPreferredLookAndFeel();
	    NativeInterface.open();
	    SwingUtilities.invokeLater(new Runnable() {
	    	public void run() {
	    		frame.getContentPane().add(new GoogleAuthenticatorUI(), BorderLayout.CENTER);
		        frame.setSize(450, 480);
		        frame.setLocation(loc);
		        frame.setVisible(true);
	        }
	    });
	}
	
	/**
	 * Takes in a temporary access token issued by Google OAuth2, and trades it for a valid
	 * access token.
	 * @param tempAccessToken
	 * @throws Exception
	 */
	private void validateAccessToken(String tempAccessToken) throws Exception {
		String url = GOOGLE_VALIDATE_TOKEN_URL;
		URL obj = new URL(url);
		HttpsURLConnection con = (HttpsURLConnection) obj.openConnection();
		
		frame.setVisible(false);
		frame.dispose();
 
		//add request header
		con.setRequestMethod(REQUEST_TYPE_POST);
		con.setRequestProperty(REQUEST_CONTENT_TYPE, CONTENT_TYPE_FORM_ENCODED);
 
		String urlParameters = String.format(GOOGLE_VALIDATE_QUERY, tempAccessToken);
 
		// Send post request
		con.setDoOutput(true);
		DataOutputStream wr = new DataOutputStream(con.getOutputStream());
		wr.writeBytes(urlParameters);
		wr.flush();
		wr.close();
 
		int responseCode = con.getResponseCode();
		AppLogger.log(String.format(LOGGER_VALIDATE_ACCESS_TOKEN, responseCode));
 
		Reader reader = new InputStreamReader(con.getInputStream());
		
		Gson gson = new GsonBuilder().create();
        GoogleAccessToken response = gson.fromJson(reader, GoogleAccessToken.class);
		
		//Close this window and get calendar items
		GoogleCalendar.startGoogleSync(response.getAccessToken());
	}

}
